const { User, Invitation, PointsTransaction } = require('../models')
const logger = require('../utils/logger')
const redis = require('../config/redis')

class InviteAntiCheatService {
  /**
   * 检查邀请是否存在作弊行为
   * @param {Object} inviteData - 邀请数据
   * @returns {Promise<Object>} 检查结果
   */
  static async checkInviteCheat(inviteData) {
    try {
      const {
        inviterId,
        inviteeId,
        inviteCode,
        ipAddress,
        userAgent,
        deviceId
      } = inviteData

      const risks = []
      let riskLevel = 'low' // low, medium, high

      // 1. 检查IP地址重复
      const ipRisk = await this.checkIPRisk(inviterId, ipAddress)
      if (ipRisk.isRisk) {
        risks.push(ipRisk)
        riskLevel = 'medium'
      }

      // 2. 检查设备指纹重复
      if (deviceId) {
        const deviceRisk = await this.checkDeviceRisk(inviterId, deviceId)
        if (deviceRisk.isRisk) {
          risks.push(deviceRisk)
          riskLevel = 'high'
        }
      }

      // 3. 检查邀请频率
      const frequencyRisk = await this.checkInviteFrequency(inviterId)
      if (frequencyRisk.isRisk) {
        risks.push(frequencyRisk)
        if (frequencyRisk.severity === 'high') {
          riskLevel = 'high'
        } else if (riskLevel === 'low') {
          riskLevel = 'medium'
        }
      }

      // 4. 检查用户行为模式
      const behaviorRisk = await this.checkUserBehavior(inviteeId, userAgent)
      if (behaviorRisk.isRisk) {
        risks.push(behaviorRisk)
        if (riskLevel === 'low') {
          riskLevel = 'medium'
        }
      }

      // 5. 检查账号关联性
      const accountRisk = await this.checkAccountAssociation(inviterId, inviteeId)
      if (accountRisk.isRisk) {
        risks.push(accountRisk)
        riskLevel = 'high'
      }

      const result = {
        isRisk: risks.length > 0,
        riskLevel,
        risks,
        allowInvite: riskLevel !== 'high',
        needManualReview: riskLevel === 'medium'
      }

      // 记录风险检查日志
      logger.info(`邀请风险检查: 邀请人 ${inviterId}, 被邀请人 ${inviteeId}, 风险等级 ${riskLevel}`, {
        risks: risks.map(r => r.type),
        result
      })

      return result
    } catch (error) {
      logger.error('邀请作弊检查失败:', error)
      // 检查失败时允许邀请，但记录日志
      return {
        isRisk: false,
        riskLevel: 'unknown',
        risks: [],
        allowInvite: true,
        needManualReview: false,
        error: error.message
      }
    }
  }

  /**
   * 检查IP地址风险
   * @param {number} inviterId - 邀请人ID
   * @param {string} ipAddress - IP地址
   * @returns {Promise<Object>} 检查结果
   */
  static async checkIPRisk(inviterId, ipAddress) {
    try {
      if (!ipAddress) {
        return { isRisk: false }
      }

      const { Op } = require('sequelize')
      
      // 检查24小时内同一IP的邀请次数
      const oneDayAgo = new Date(Date.now() - 24 * 60 * 60 * 1000)
      
      const sameIPInvites = await Invitation.count({
        where: {
          inviter_id: inviterId,
          created_at: { [Op.gte]: oneDayAgo }
        },
        include: [{
          model: User,
          as: 'invitee',
          where: {
            // 这里需要在User模型中添加last_login_ip字段来存储IP
            // 暂时用创建时间作为替代检查
          }
        }]
      })

      // 检查Redis中的IP记录
      const ipKey = `invite_ip:${inviterId}:${ipAddress}`
      const ipCount = await redis.get(ipKey) || 0

      if (parseInt(ipCount) >= 3) {
        return {
          isRisk: true,
          type: 'ip_frequency',
          message: '同一IP地址邀请次数过多',
          severity: 'medium',
          details: { ipAddress, count: ipCount }
        }
      }

      // 记录IP使用次数
      await redis.setex(ipKey, 86400, parseInt(ipCount) + 1) // 24小时过期

      return { isRisk: false }
    } catch (error) {
      logger.error('IP风险检查失败:', error)
      return { isRisk: false }
    }
  }

  /**
   * 检查设备指纹风险
   * @param {number} inviterId - 邀请人ID
   * @param {string} deviceId - 设备ID
   * @returns {Promise<Object>} 检查结果
   */
  static async checkDeviceRisk(inviterId, deviceId) {
    try {
      const deviceKey = `invite_device:${inviterId}:${deviceId}`
      const deviceCount = await redis.get(deviceKey) || 0

      if (parseInt(deviceCount) >= 2) {
        return {
          isRisk: true,
          type: 'device_reuse',
          message: '同一设备多次邀请',
          severity: 'high',
          details: { deviceId, count: deviceCount }
        }
      }

      // 记录设备使用次数
      await redis.setex(deviceKey, 86400 * 7, parseInt(deviceCount) + 1) // 7天过期

      return { isRisk: false }
    } catch (error) {
      logger.error('设备风险检查失败:', error)
      return { isRisk: false }
    }
  }

  /**
   * 检查邀请频率
   * @param {number} inviterId - 邀请人ID
   * @returns {Promise<Object>} 检查结果
   */
  static async checkInviteFrequency(inviterId) {
    try {
      const { Op } = require('sequelize')
      
      // 检查1小时内邀请次数
      const oneHourAgo = new Date(Date.now() - 60 * 60 * 1000)
      const hourlyCount = await Invitation.count({
        where: {
          inviter_id: inviterId,
          created_at: { [Op.gte]: oneHourAgo }
        }
      })

      if (hourlyCount >= 10) {
        return {
          isRisk: true,
          type: 'high_frequency',
          message: '邀请频率过高',
          severity: 'high',
          details: { hourlyCount, limit: 10 }
        }
      }

      // 检查24小时内邀请次数
      const oneDayAgo = new Date(Date.now() - 24 * 60 * 60 * 1000)
      const dailyCount = await Invitation.count({
        where: {
          inviter_id: inviterId,
          created_at: { [Op.gte]: oneDayAgo }
        }
      })

      if (dailyCount >= 50) {
        return {
          isRisk: true,
          type: 'daily_limit_exceeded',
          message: '日邀请次数超限',
          severity: 'medium',
          details: { dailyCount, limit: 50 }
        }
      }

      return { isRisk: false }
    } catch (error) {
      logger.error('邀请频率检查失败:', error)
      return { isRisk: false }
    }
  }

  /**
   * 检查用户行为模式
   * @param {number} userId - 用户ID
   * @param {string} userAgent - 用户代理
   * @returns {Promise<Object>} 检查结果
   */
  static async checkUserBehavior(userId, userAgent) {
    try {
      // 检查用户注册时间（新注册用户立即被邀请可能有风险）
      const user = await User.findByPk(userId)
      if (!user) {
        return { isRisk: false }
      }

      const registrationTime = new Date(user.created_at)
      const now = new Date()
      const timeDiff = now - registrationTime

      // 注册后5分钟内被邀请视为可疑
      if (timeDiff < 5 * 60 * 1000) {
        return {
          isRisk: true,
          type: 'quick_registration',
          message: '注册后立即被邀请',
          severity: 'medium',
          details: { 
            registrationTime: registrationTime.toISOString(),
            timeDiff: Math.round(timeDiff / 1000) 
          }
        }
      }

      // 检查User-Agent是否异常
      if (userAgent && this.isAbnormalUserAgent(userAgent)) {
        return {
          isRisk: true,
          type: 'abnormal_user_agent',
          message: '异常的用户代理',
          severity: 'low',
          details: { userAgent }
        }
      }

      return { isRisk: false }
    } catch (error) {
      logger.error('用户行为检查失败:', error)
      return { isRisk: false }
    }
  }

  /**
   * 检查账号关联性
   * @param {number} inviterId - 邀请人ID
   * @param {number} inviteeId - 被邀请人ID
   * @returns {Promise<Object>} 检查结果
   */
  static async checkAccountAssociation(inviterId, inviteeId) {
    try {
      // 检查是否存在相互邀请
      const mutualInvite = await Invitation.findOne({
        where: {
          inviter_id: inviteeId,
          invitee_id: inviterId
        }
      })

      if (mutualInvite) {
        return {
          isRisk: true,
          type: 'mutual_invitation',
          message: '存在相互邀请',
          severity: 'high',
          details: { mutualInviteId: mutualInvite.id }
        }
      }

      // 检查手机号相似性（如果有手机号信息）
      const [inviter, invitee] = await Promise.all([
        User.findByPk(inviterId, { attributes: ['phone'] }),
        User.findByPk(inviteeId, { attributes: ['phone'] })
      ])

      if (inviter?.phone && invitee?.phone) {
        const similarity = this.calculatePhoneSimilarity(inviter.phone, invitee.phone)
        if (similarity > 0.8) {
          return {
            isRisk: true,
            type: 'similar_phone',
            message: '手机号高度相似',
            severity: 'medium',
            details: { similarity }
          }
        }
      }

      return { isRisk: false }
    } catch (error) {
      logger.error('账号关联性检查失败:', error)
      return { isRisk: false }
    }
  }

  /**
   * 检查User-Agent是否异常
   * @param {string} userAgent - 用户代理字符串
   * @returns {boolean} 是否异常
   */
  static isAbnormalUserAgent(userAgent) {
    // 检查是否为常见的爬虫或自动化工具
    const suspiciousPatterns = [
      /bot/i,
      /crawler/i,
      /spider/i,
      /scraper/i,
      /curl/i,
      /wget/i,
      /python/i,
      /java/i,
      /postman/i
    ]

    return suspiciousPatterns.some(pattern => pattern.test(userAgent))
  }

  /**
   * 计算手机号相似度
   * @param {string} phone1 - 手机号1
   * @param {string} phone2 - 手机号2
   * @returns {number} 相似度 (0-1)
   */
  static calculatePhoneSimilarity(phone1, phone2) {
    if (!phone1 || !phone2) return 0
    
    // 简单的相似度计算：相同字符数 / 总字符数
    const len1 = phone1.length
    const len2 = phone2.length
    const maxLen = Math.max(len1, len2)
    
    let sameCount = 0
    for (let i = 0; i < Math.min(len1, len2); i++) {
      if (phone1[i] === phone2[i]) {
        sameCount++
      }
    }
    
    return sameCount / maxLen
  }

  /**
   * 处理风险邀请
   * @param {Object} riskResult - 风险检查结果
   * @param {Object} inviteData - 邀请数据
   * @returns {Promise<Object>} 处理结果
   */
  static async handleRiskInvite(riskResult, inviteData) {
    try {
      const { inviterId, inviteeId, inviteCode } = inviteData

      if (!riskResult.allowInvite) {
        // 高风险，拒绝邀请
        logger.warn(`拒绝高风险邀请: 邀请人 ${inviterId}, 被邀请人 ${inviteeId}`, {
          risks: riskResult.risks
        })

        return {
          success: false,
          message: '邀请失败，请稍后重试',
          riskBlocked: true
        }
      }

      if (riskResult.needManualReview) {
        // 中等风险，需要人工审核
        logger.info(`邀请需要人工审核: 邀请人 ${inviterId}, 被邀请人 ${inviteeId}`, {
          risks: riskResult.risks
        })

        // 创建待审核的邀请记录
        const invitation = await Invitation.create({
          inviter_id: inviterId,
          invitee_id: inviteeId,
          invite_code: inviteCode,
          register_time: new Date(),
          status: 0, // 待审核状态
          risk_data: JSON.stringify(riskResult)
        })

        return {
          success: true,
          message: '邀请已提交，正在审核中',
          needReview: true,
          invitation
        }
      }

      // 低风险或无风险，正常处理
      return {
        success: true,
        allowNormalProcess: true
      }
    } catch (error) {
      logger.error('处理风险邀请失败:', error)
      throw error
    }
  }

  /**
   * 获取用户风险统计
   * @param {number} userId - 用户ID
   * @returns {Promise<Object>} 风险统计
   */
  static async getUserRiskStats(userId) {
    try {
      const { Op } = require('sequelize')
      
      // 获取最近30天的邀请记录
      const thirtyDaysAgo = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000)
      
      const invitations = await Invitation.findAll({
        where: {
          inviter_id: userId,
          created_at: { [Op.gte]: thirtyDaysAgo }
        }
      })

      const totalInvites = invitations.length
      const riskInvites = invitations.filter(inv => inv.risk_data).length
      const pendingReview = invitations.filter(inv => inv.status === 0).length

      return {
        totalInvites,
        riskInvites,
        pendingReview,
        riskRate: totalInvites > 0 ? Math.round((riskInvites / totalInvites) * 100) : 0,
        trustLevel: this.calculateTrustLevel(totalInvites, riskInvites)
      }
    } catch (error) {
      logger.error('获取用户风险统计失败:', error)
      throw error
    }
  }

  /**
   * 计算用户信任等级
   * @param {number} totalInvites - 总邀请数
   * @param {number} riskInvites - 风险邀请数
   * @returns {string} 信任等级
   */
  static calculateTrustLevel(totalInvites, riskInvites) {
    if (totalInvites === 0) return 'new'
    
    const riskRate = riskInvites / totalInvites
    
    if (riskRate === 0 && totalInvites >= 10) return 'high'
    if (riskRate < 0.1) return 'medium'
    if (riskRate < 0.3) return 'low'
    return 'very_low'
  }
}

module.exports = InviteAntiCheatService